package helper

// 短信验证码

import (
	"errors"
	"strings"
	"sync"
	"time"

	"github.com/astaxie/beego/config"
)

// CaptchaServer 验证码服务
var CaptchaServer CaptchaService

// CaptchaService 验证码服务接口
type CaptchaService interface {
	Gen(string) (string, error)
	Validate(string, string) bool
	Start()
}

// Captcha 验证码
type Captcha struct {
	Phone  string
	Code   string
	Expire time.Time
}

// DefaultCaptchaServer 默认验证码服务
type DefaultCaptchaServer struct {
	list     map[string]Captcha
	lock     sync.RWMutex
	Duration time.Duration
	Expire   time.Duration
}

// NewDefaultCaptchaServer 生成新服务
func NewDefaultCaptchaServer(interval, expire time.Duration) *DefaultCaptchaServer {
	return &DefaultCaptchaServer{
		Duration: interval,
		Expire:   expire,
		list:     make(map[string]Captcha),
	}
}

// Gen 生产验证码
func (s DefaultCaptchaServer) Gen(phone string) (string, error) {
	// TODO
	captcha := "123456"

	s.lock.Lock()

	s.list[phone] = Captcha{
		Phone:  phone,
		Code:   captcha,
		Expire: time.Now().Add(s.Expire),
	}

	s.lock.Unlock()

	return captcha, nil
}

// Validate 校验验证码
func (s DefaultCaptchaServer) Validate(phone, captcha string) bool {

	s.lock.RLock()

	phoneCaptcha, ok := s.list[phone]
	if !ok {
		return false
	}

	s.lock.RUnlock()

	return phoneCaptcha.Code == captcha
}

// Start 启动服务
func (s DefaultCaptchaServer) Start() {
	go func() {
		for now := range time.Tick(s.Duration) {
			s.lock.RLock()
			list := s.list
			s.lock.RUnlock()

			for phone, val := range list {
				if val.Expire.Before(now) {
					s.lock.Lock()
					delete(s.list, phone)
					s.lock.Unlock()
				}
			}
		}
	}()
}

// InnerCaptchaServer 内部短信验证码接口
type InnerCaptchaServer struct {
	sourceSrv string
	validSrv  string
	httpCli   *HttpClient
}

// NewInnerCaptchaServer 实例创建
func NewInnerCaptchaServer(sourceSrv, validSrv string) *InnerCaptchaServer {
	return &InnerCaptchaServer{
		sourceSrv: sourceSrv,
		validSrv:  validSrv,
		httpCli:   NewHttpClient(),
	}
}

// Gen 生产验证码
func (s InnerCaptchaServer) Gen(phone string) (string, error) {
	buf := struct {
		Flag bool
		Msg  string
	}{}

	url := strings.Replace(s.sourceSrv, "${phone}", phone, -1)

	if err := s.httpCli.GetWithResult(url, &buf); err != nil {
		return "", err
	}

	if !buf.Flag {
		return "", errors.New("短信发送失败: " + buf.Msg)
	}

	return "", nil
}

// Validate 校验验证码
func (s InnerCaptchaServer) Validate(phone, captcha string) bool {
	buf := struct {
		Flag bool
		Msg  string
	}{}

	url := strings.NewReplacer("${phone}", phone, "${captcha}", captcha).Replace(s.validSrv)

	if err := s.httpCli.GetWithResult(url, &buf); err != nil {
		return false
	}

	if !buf.Flag {
		return false
	}

	return true
}

// Start 启动服务
func (s InnerCaptchaServer) Start() {}

var _ CaptchaService = DefaultCaptchaServer{}
var _ CaptchaService = InnerCaptchaServer{}

// // RunDefaultCaptchaServer 启动默认服务
// func RunDefaultCaptchaServer(interval, expire time.Duration) {
// 	CaptchaServer = NewDefaultCaptchaServer(interval, expire)
// 	CaptchaServer.Start()
// }

func init() {
	conf, _ := config.NewConfig("ini", "conf/captcha.conf")
	src := conf.String("srouce")
	valid := conf.String("validator")

	CaptchaServer = NewInnerCaptchaServer(src, valid)
}
